iT邦幫忙

2025 iThome 鐵人賽

DAY 4
1
Software Development

30 天 Effective C++ 大挑戰!!系列 第 4

[Day 4] Constructors, Destructors, and Assignment Operators II

  • 分享至 

  • xImage
  •  

風和日麗的一天,帶著愉快學習的心情,提早半小時就到公司了。早起的鳥兒有蟲吃,早起的 Yoyo 有書唸,繼續閱讀《Effective C++》的第二章吧!

9. Never call virtual functions during construction and destruction

首先簡單解釋 知識點 7 提到的「基底類別」和「衍生類別」。兩者皆是物件導向程式設計中的概念,用於描述類別之間的繼承關係。

  • Base class:又稱為父類別,提供共同功能和屬性的類別。
  • Derived class:又稱為子類別,基於基底類別擴展的新類別,繼承了基底類別的屬性和方法。

執行期間 object 的型別會從 base class 轉換到 derived class,並於解構銷毀時再回到 base class。

當 derived class 的物件開始初始化時,會先執行 base class 的建構子,此時物件便不算是 derived class。若在在這個階段呼叫虛擬函數,系統只會執行 base class 版本的函數。只有等 derived class 的建構子開始執行並完成初始化後,虛擬函數才會指向 derived class 的版本。

因此,base class 的建構子及解構子中均無法執行 derived class 的虛擬函數。為了避免重複程式碼,常見的做法是將建構子的主要任務提取到 init() 函數中。不過需注意此 init() 函數裡依舊不能呼叫虛擬函數。

10. Have assignment operators return a reference to *this

賦值的過程是 right-associative。舉例來說,下方的 chain of assignments:

int x, y, z;
int x = y = z = 15;

亦可寫為:

x = (y = (z = 15));

進行賦值操作時,回傳的是 left-hand argument 的 reference,這使得賦值運算能夠實現 chain 的效果。基於此約定,我們在實作 assignment operator 時也應遵循這個慣例,確保程式行為的一致性:

class Widget
{
public:
    Widget& operator= (const Widget& rhs)
    {
        ...
        return *this;
    }
}

11. Handle assignment to self in operator=

雖然聽起來很不可思議,但實務上我們很常隱晦地把 object 賦值給它自己:

a[i] = a[j];
*px = *py;

事實上,即使是不同型別的 object 依舊能引用或指向到同一個 object,例如 base class 與 derived class。為了確保 self-assignment 的安全性,可以使用 identity test,在 operator= 時先檢查是否為指派給自己:

Widget& Widget::operator=(const Widget& rhs)
{
    if(this == &rhs) return *this;
    
    delete pb;
    pb = new Bitmap(*rhs.pb);
    return *this;
}

若想更進一步確保 exception-safe,書中有提到這種寫法:

Widget& Widget::operator=(const Widget& rhs)
{
    Bitmap *pOrig = pb;
    pb = new Bitmap(*rhs.pb);
    delete pOrig;
    return *this;
}

也可以採用 copy and swap 的小技巧,讓程式更有效率:

Widget& Widgget::operator=(Widget rhs)
{
    swap(rhs);
    return *this;
}

12. Copy all parts of an object

  • 新增成員變數時,記得在 copy constructor 和 assignment operator 中處理它們。若不慎忽略這點,編譯器會認為我們想自行宣告新的 copy functon,並不會出現任何警示訊息。
  • derived class 在繼承時需複製 base class。通常 base class 的成員為 private,因此正確做法是讓 derived class 調用 base class 的 copy constructor。

知識點 5 有稍微介紹過 copy constructor 和 copy assignment operator 的呼叫時機:copy constructor會創建一個新的 object;而 copy assignment operator 則用來修改一個已存在的 object。因此請特別留意兩者不應互相呼叫!


上一篇
[Day 3] Constructors, Destructors, and Assignment Operators I
下一篇
[Day 5] 中場休息 Q&A小測驗!!
系列文
30 天 Effective C++ 大挑戰!!30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言